package cn.edu.zut.sunday.sst.service.impl;

import cn.edu.zut.sunday.constant.SstDatasetInfo;
import cn.edu.zut.sunday.sst.dao.SstInfoRepository;
import cn.edu.zut.sunday.sst.domain.SstInfo;
import cn.edu.zut.sunday.sst.service.InsertDataService;
import cn.edu.zut.sunday.utils.ReloadFileUtils;
import com.google.common.collect.Maps;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class InsertDataServiceImpl implements InsertDataService {

    private SstInfoRepository sstInfoRepository;
    @Autowired
    public void setSstInfoRepository(SstInfoRepository sstInfoRepository) {
        this.sstInfoRepository = sstInfoRepository;
    }
    /**
     * 读取四个文件，加载其中的数据到数据库中： 1. labels.txt 2. sentences.txt 3. token.txt 4. tree.txt
     *
     * @return 是否插入成功
     */
    @Override
    public boolean initDatabase() {
        try {
            List<File> files = ReloadFileUtils.getFiles(SstDatasetInfo.DATASET_FILE_PATH);
            final Map<String, File> fileMap = files.stream()
              .collect(Collectors.toMap(File::getName, v -> v));
            Map<Integer, String> id2TokenMap = readLinesInfo(fileMap,
              SstDatasetInfo.TOKENS_FILE);
            Map<Integer, String> id2TreeMap     = readLinesInfo(fileMap, SstDatasetInfo.TREE_FILE);
            Map<Integer, Float>  id2LabelMap    = readLabelInfo(fileMap);
            Map<Integer, String> id2SentenceMap = readSentenceInfo(fileMap);
            // 清空数据库
            sstInfoRepository.deleteAll();
            // 插入数据，id自增
            // 不设置具体Id；这样可以避免测试时占用id导致无法保存实体
            final List<SstInfo> entityList = id2SentenceMap
              .keySet()
              .stream()
              .map(idx -> {
                  final SstInfo sstInfo = new SstInfo();
                  sstInfo.setSentence(id2SentenceMap.get(idx));
                  sstInfo.setLabel(id2LabelMap.get(idx));
                  sstInfo.setTokens(id2TokenMap.get(idx));
                  sstInfo.setTree(id2TreeMap.get(idx));
                  sstInfo.setDateCreated(new Date());
                  sstInfo.setDateModified(new Date());
                  return sstInfo;
              }).collect(Collectors.toList());
            // 插入数据库，如果已经存在则会是更新数据
            sstInfoRepository.saveAllAndFlush(entityList);
            return true;
        } catch (Exception e) {
            log.error("read dataset failed. path is: [ {} ], error: {}",
              SstDatasetInfo.DATASET_FILE_PATH, e.getMessage());
        }

        return false;
    }

    @Override
    public String datasetName() {
        return SstDatasetInfo.DATASET_NAME;
    }

    private Map<Integer, String> readLinesInfo(Map<String, File> fileMap, String fileName) {
        final File file = fileMap.getOrDefault(fileName, null);
        if (file == null) {return Maps.newTreeMap();}
        try {
            final List<String> allLines = ReloadFileUtils.readFileAllLines(file);
            log.info("{} first line: {}", fileName, allLines.get(0));
            final HashMap<Integer, String> id2KeyMap = Maps.newHashMap();
            for (int i = 0; i < allLines.size(); i++) {
                // 这里是id从1开始累加
                id2KeyMap.put(i+1, allLines.get(i));
            }
            return id2KeyMap;
        } catch (IOException e) {
            log.error("read file failed. File name is: [ {} ], error: {}",
              fileName, e.getMessage());
        }
        return Maps.newTreeMap();
    }

    private Map<Integer, String> readSentenceInfo(Map<String, File> fileMap) {
        final File file = fileMap.getOrDefault(SstDatasetInfo.SENTENCES_FILE, null);
        if (file == null) {return Maps.newTreeMap();}
        try {
            final List<String> allLines = ReloadFileUtils.readFileAllLines(file);
            // 删除第一行的行描述
            allLines.remove(0);
            log.info("{} first line: {}", SstDatasetInfo.SENTENCES_FILE, allLines.get(0));
            // 分割每一行
            return allLines.stream()
              .map(line -> line.split(SstDatasetInfo.SENTENCES_SEPARATOR)).collect(
                Collectors.toMap(val -> Integer.parseInt(val[0]), val -> val[1]));
        } catch (IOException e) {
            log.error("read dataset failed. path is: [ {} ], error: {}",
              SstDatasetInfo.SENTENCES_FILE, e.getMessage());
        }
        return Maps.newTreeMap();
    }

    private Map<Integer, Float> readLabelInfo(Map<String, File> fileMap) {
        final File file = fileMap.getOrDefault(SstDatasetInfo.LABELS_FILE, null);
        if (file == null) {return Maps.newTreeMap();}
        try {
            final List<String> allLines = ReloadFileUtils.readFileAllLines(file);
            // 删除第一行的行描述
            allLines.remove(0);
            log.info("{} first line: {}", SstDatasetInfo.LABELS_FILE, allLines.get(0));
            // 分割每一行
            return allLines.stream()
              .map(line -> line.split(SstDatasetInfo.LABELS_SEPARATOR)).collect(
                Collectors.toMap(val -> Integer.parseInt(val[0]), val -> Float.parseFloat(val[1])));
        } catch (IOException e) {
            log.error("read dataset failed. path is: [ {} ], error: {}",
              SstDatasetInfo.LABELS_FILE, e.getMessage());
        }

        return Maps.newTreeMap();
    }
}
